// Entity.h
struct ANIM
{
	int nOfFrames;
	int *frames;
	float fps;
	
};

class Entity // the thing that is actually displayed is called an entity :)
{
	int baseTex[2];
	int nOfAnims;
	ANIM* Animation;
	TIMER* timer; // each animation gets his own timer
	string directory;
	string ext1;
	string ext2;
	float fActiveFrame;
	
	string nonAnimFile;

	

	int activeAnim;
	int activeFrame;

	// random shit
	string strAnim;
	string strFrame;


public:	
	float width;
	float height;
		   
	int xPos,yPos;
	float scale;
	int rotation;
	int entID; // entity register entry
	string entName;

	Entity()
	{
		entName = "NULL";
		fActiveFrame=0;
		directory = "Entity\\";
		ext1 = ".txt";
		ext2 = ".raw";
		nOfAnims = 0;
		baseTex[0] = 0;
		baseTex[1] = 0;

		xPos =0;
		yPos =0;
		scale = 10;
		rotation = 0;

		activeAnim  = 0;
		activeFrame = 0;

		strAnim = "\\ANIM_";
		strFrame = "\\FRAME_";
	}

	~Entity()
	{
		//cout << "Deleting entity.." << endl;
		//for(int counter = 0;counter < nOfAnims;counter++)
		//{
			//glDeleteTextures(Animation[counter].nOfFrames,(const GLuint*)Animation[counter].frames);
			//delete[] Animation[counter].frames;
		//}

		//cout << "Animated sprites deleted." << endl;

		//if(nOfAnims==0)
			//glDeleteTextures(1,(GLuint*)baseTex);
	}

	void destroy()
	{
		for(int counter = 0;counter < nOfAnims;counter++)
			glDeleteTextures(Animation[counter].nOfFrames,(const GLuint*)Animation[counter].frames);

		if(nOfAnims==0)
			glDeleteTextures(1,(GLuint*)baseTex);
	}

	void Load(string name)
	{
		cout << "    --> Loading entity: \"" << name.c_str() << "\": ";
		entName = name;

		string strFile = directory+name+"\\"+name+ext1;
		const char* file = strFile.c_str();

		cout << file << endl;

		int fps =0;

		ifstream txtFile(file);
		if(txtFile.is_open())
		{
			txtFile >> nOfAnims;
			txtFile >> width;
			txtFile >> height;
			txtFile >> nonAnimFile;

			if(nOfAnims != 0)
			{
				//cout << "  --> " << nOfAnims << " anims." << endl;
				Animation = new ANIM[nOfAnims];
				timer = new TIMER[nOfAnims];
				for(int currentAnim =0;currentAnim < nOfAnims;currentAnim++)
				{
					txtFile >> Animation[currentAnim].nOfFrames;
					txtFile >> fps;
					timer[currentAnim].setInterval(1000/fps); // set speed for the timer in fps
					Animation[currentAnim].fps = (float)fps;
					Animation[currentAnim].frames = new int[Animation[currentAnim].nOfFrames]; // allocate memory for frames
				}

			}
			else
			{
				//cout << "  --> no anims." << endl;
			}

			// load textures/frames

			if(nOfAnims==0) // only load base image
			{
				strFile = directory+name+"\\"+name+ext2;
				file = strFile.c_str();
				baseTex[0] = loadRaw(width,height,file);
			}
			else
			{
				for(int currentAnim = 0;currentAnim < nOfAnims;currentAnim++)
				{
					for(int currentFrame = 0;currentFrame < Animation[currentAnim].nOfFrames;currentFrame++)
					{
						strFile = directory+name+strAnim+intToString(currentAnim)+strFrame+intToString(currentFrame)+ext2;
						file = strFile.c_str();

						Animation[currentAnim].frames[currentFrame] = loadRaw(width,height,file);
					}
				}
			}
		}
		else
		{
			cout << endl << "Error: Could not open " << txtFile << endl;
		}

	}

	void render()
	{
		setColor3f(1,1,1);

		if(nOfAnims==0)
		{
			pushMatrix();////////////////////
			enableTexture();
			bindTexture(baseTex[0]);


			
			translatef(xPos,yPos,0);
			scalef(scale*0.1,scale*0.1,1);
			rotatef(0,0,1,rotation);

			drawQuad(-(width/2),-(height/2),width/2,height/2);

			

			

			disableTexture();
			popMatrix();//////////////////
		}
		else
		{
			glPushMatrix(); //////////////

			enableTexture();
			bindTexture(Animation[activeAnim].frames[activeFrame]);

			

			translatef(xPos,yPos,0);
			scalef(scale*0.1,scale*0.1,1);
			rotatef(0,0,1,rotation);

			drawQuad(-(width/2),-(height/2),width/2,height/2);

			

			
			disableTexture();

			if(fActiveFrame + getLastTime()/1000*Animation[activeAnim].fps < Animation[activeAnim].nOfFrames)
				fActiveFrame += getLastTime()/1000*Animation[activeAnim].fps;
			else
				fActiveFrame = 0;

			activeFrame = fActiveFrame;

			/*for(int counter = 0;counter < timer[activeAnim].state();counter++) // the timer will determine when and how many times this will execute
			{
				if(activeFrame < Animation[activeAnim].nOfFrames-1)
				{
					//cout << "Increasing Frame" << endl;
					activeFrame++;
				}
				else
					activeFrame = 0;
			}*/


			popMatrix();  /////////////////////

		}
	}

	void setActiveAnim(int animId)
	{
		if(animId < nOfAnims)
		{
			activeAnim = animId;
			activeFrame = 0;
		}
		else
			cout << "ERROR: Animation" << animId << " missing in sprite \"" << entName << "\"!" << endl; 
	}
};

class EntLayer
{

public:

	int nOfEnts;
	Entity* entity;

	EntLayer()
	{
		nOfEnts = 0;
	}

	void render()
	{
		for(int counter =0;counter < nOfEnts;counter++)
		{
			entity[counter].render();
		}
	}
};

class EntHandler
{
	string strFile;
	const char* file;

	
	// random shit

	string file1;
	string file2;
	string folder;

	bool mapLoaded;

	int *entsInMap;
	int nOfAvailableEntities;
	string* availableEnts;	
	int *temp;

public:
	int nOfEntsInMap;
	Entity* EntTemplate;

	EntLayer layer1;
	EntLayer layer2;

	EntHandler()
	{
		file1 = "EntityLayer1.txt";
	    file2 = "EntityLayer2.txt";
		folder = "Maps\\";
		mapLoaded=false;
		nOfEntsInMap = 0;

	}

	void unLoad()
	{
		if(mapLoaded)
		{
			
			for(int counter = 0;counter < layer1.nOfEnts;counter++)
				layer1.entity[counter].destroy();
			for(int counter = 0;counter < layer2.nOfEnts;counter++)
				layer2.entity[counter].destroy();
			
		}
	}

	void Load(string mapname)
	{
		strFile = folder+mapname+"\\"+file1;
		file = strFile.c_str();

		ifstream obLayer1(file);
		if(obLayer1.is_open())
		{
			obLayer1 >> layer1.nOfEnts;
			layer1.entity = new Entity[layer1.nOfEnts];

			for(int counter = 0;counter < layer1.nOfEnts;counter++)
			{
				obLayer1 >> layer1.entity[counter].entID;
				obLayer1 >> layer1.entity[counter].xPos;
				obLayer1 >> layer1.entity[counter].yPos;
				obLayer1 >> layer1.entity[counter].rotation;
				obLayer1 >> layer1.entity[counter].scale;
			}
		}
		else
		{
			cout << "Why the fuck is " << file << " not there?" << endl;
			return;
		}
		obLayer1.close();

		strFile = folder+mapname+"\\"+file2;
		file = strFile.c_str();

		ifstream obLayer2(file);
		if(obLayer2.is_open())
		{
			obLayer2 >> layer2.nOfEnts;
			layer2.entity = new Entity[layer2.nOfEnts];

			for(int counter = 0;counter < layer2.nOfEnts;counter++)
			{
				obLayer2 >> layer2.entity[counter].entID;
				obLayer2 >> layer2.entity[counter].xPos;
				obLayer2 >> layer2.entity[counter].yPos;
				obLayer2 >> layer2.entity[counter].rotation;
				obLayer2 >> layer2.entity[counter].scale;
			}
		}
		else
			cout << "Why the fuck is " << file << " not there?" << endl;

		obLayer2.close();
		///////////////////////////////////////////////////////
		// dynamically allocate the entities

		//cout << "lololol" << endl;
		temp = new int[100];
		for(int curIndex = 0;curIndex < 100;curIndex++)
			temp[curIndex] = 0;

		nOfEntsInMap =0;

		for(int counter = 0;counter < layer1.nOfEnts;counter++)
		{
			if(isNumberInArray(layer1.entity[counter].entID,temp,nOfEntsInMap)==false)
			{
				//cout << "Entity " << layer1.entity[counter].entID << " is not yet in array" << endl;
				temp[nOfEntsInMap] = layer1.entity[counter].entID;
				nOfEntsInMap++;
			}
		}

		for(int counter = 0;counter < layer2.nOfEnts;counter++)
		{
			if(isNumberInArray(layer2.entity[counter].entID,temp,nOfEntsInMap)==false)
			{
				//cout << "Entity " << layer2.entity[counter].entID << " is not yet in array" << endl;
				temp[nOfEntsInMap] = layer2.entity[counter].entID;
				nOfEntsInMap++;
			}
		}


		cout << "Loading " << nOfEntsInMap << " entities." << endl;
		
		entsInMap = new int[nOfEntsInMap];

		for(int counter =0;counter < nOfEntsInMap;counter++)
		{
			
			entsInMap[counter] = temp[counter];
			//cout << "Entlist[" << counter << "] = " << entsInMap[counter] << endl;
		}

		//cout << "lololol" << endl;
		delete[] temp;

		//cout << "lololol" << endl;

		ifstream entDefs("Data\\Registers\\_EntityRegister.txt");
		if(entDefs.is_open())
		    nOfAvailableEntities = count(std::istreambuf_iterator<char>(entDefs), std::istreambuf_iterator<char>(), '\n');
		else
		{
			nOfAvailableEntities =0;
			cout << "An error occured." << endl;
		}
		entDefs.close();

		//cout << "lololol" << endl;

		availableEnts = new string[nOfAvailableEntities];

		ifstream entDef("Data\\Registers\\_EntityRegister.txt");
		if(entDef.is_open())
		{
			for(int counter =0;counter < nOfAvailableEntities;counter++)
			{
				entDef >> availableEnts[counter];
			}
		}
		else
			cout << "ERROR: could not open Data\\Registers\\_EntityRegister.txt bitch.." << endl;

		entDef.close();

		EntTemplate = new Entity[nOfEntsInMap];
		

		for(int counter = 0;counter < nOfEntsInMap;counter++)
		{
			EntTemplate[counter].Load(availableEnts[entsInMap[counter]]);
		}

		int tempPosX;
		int tempPosY;
		int tempRot;
		int tempScale;

		for(int counter = 0;counter < layer1.nOfEnts;counter++)
		{
			for(int subCount =0;subCount < nOfAvailableEntities;subCount++)
			{
				if(layer1.entity[counter].entID==entsInMap[subCount])
				{
					tempPosX = layer1.entity[counter].xPos;
					tempPosY = layer1.entity[counter].yPos;
					tempScale = layer1.entity[counter].scale;
					tempRot = layer1.entity[counter].rotation;
					layer1.entity[counter] = EntTemplate[subCount];
					layer1.entity[counter].xPos = tempPosX;
					layer1.entity[counter].yPos = tempPosY;
					layer1.entity[counter].scale = tempScale;
					layer1.entity[counter].rotation = tempRot;
					subCount = 9699999;
				}
			}
		}
		for(int counter = 0;counter < layer2.nOfEnts;counter++)
		{
			for(int subCount =0;subCount < nOfAvailableEntities;subCount++)
			{
				if(layer2.entity[counter].entID==entsInMap[subCount])
				{
					tempPosX = layer2.entity[counter].xPos;
					tempPosY = layer2.entity[counter].yPos;
					tempScale = layer2.entity[counter].scale;
					tempRot = layer2.entity[counter].rotation;
					layer2.entity[counter] = EntTemplate[subCount];
					layer2.entity[counter].xPos = tempPosX;
					layer2.entity[counter].yPos = tempPosY;
					layer2.entity[counter].scale = tempScale;
					layer2.entity[counter].rotation = tempRot;
					subCount = 9699999;
				}
			}
		}
		mapLoaded=true;
	}
};

